
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Xml;
using System.Diagnostics;

using Swaf;
using Swaf.Call;
using Swaf.Config;

namespace Swaf.Messaging
{
	/// <summary>
	/// Summary description for MsgManager.
	/// </summary>
	public class MessagingListenerManager : IConfigPartner
	{
		protected IApplication m_app;
		protected IList m_listenerGroups;

		static private IClassFactory s_messagingSystemFactory;
		internal IClassFactory MessagingSystemFactory 
		{
			get
			{
				if(s_messagingSystemFactory == null)
					s_messagingSystemFactory = Application.currentApp.factories["MessagingSystems"];
				return s_messagingSystemFactory;
			}
		}

		public MessagingListenerManager(IApplication app)
		{
				m_app = app;
				m_listenerGroups = new ArrayList();
		}

		public void registerForConfig(IConfigManager config)
		{
			config.registerHandler("...<MessagingListeners>", new ListenerGroupConfigHandler(this));
			config.registerHandler("...<MessagingListeners> <Listener>", new ListenerDefinitionConfigHandler(this));
		}

		public void checkConfigStatus()
		{
			if(!m_app.inBrowseMode)
				foreach(MessagingListenerGroup group in m_listenerGroups)
					group.start();
		}

		internal MessagingListenerGroup createListenerGroup(string msgSystem)
		{
			MessagingListenerGroup group = null;

			try
			{
				IMessagingSystem msgSys = (IMessagingSystem)MessagingSystemFactory.createFromNickName(m_app.resMgr.resolve(msgSystem));
				group = new MessagingListenerGroup(msgSys);
				m_listenerGroups.Add(group);
			}
			catch(Exception e)
			{
			}

			return group;
		}

		internal IMessagingListener createListener(IMessagingSystem msgSys, string source, string connectionName, string processingFailureQueue, string historyQueue)
		{
			IMessagingListener listener = null;

			try
			{
				//The other string params being passed into the MessagingListener object are not resolved through the resMgr because
				//they will be resolved at the last minute when it is told to start listening.
				listener = new MessagingListener(msgSys, m_app.resMgr.resolve(source), m_app.resMgr.resolve(connectionName), m_app.resMgr.resolve(processingFailureQueue), m_app.resMgr.resolve(historyQueue));
			}
			catch(Exception e)
			{
			}

			return listener;
		}
	}

	class ListenerDefinitionConfigHandler : ConfigHandler
	{
		protected MessagingListenerManager m_mgr;

		//The only valid attributes are "class"
		protected static string[] s_legalAttributes = new string[]{"source","connection","processingFailureQueue","historyQueue"};			
		public ListenerDefinitionConfigHandler(MessagingListenerManager mgr)
		{
			m_mgr = mgr;
		}

		public override void  executeBefore(IConfigElement configInfo)
		{
			IApplication app = (IApplication)configInfo.Context["app"];

			configInfo.checkIllegalAttributes(s_legalAttributes);
			string className = configInfo.getAttribute("class");

			try
			{
				IClassFactory callFactory = Application.currentApp.factories["CallTypes"];
				string msgSys = configInfo.Context["MessagingSystem"].ToString();
				MessagingListenerGroup group = (MessagingListenerGroup)configInfo.Context["MessagingGroup"];
				if(msgSys != null && msgSys != "")
				{
					IMessagingListener listener = m_mgr.createListener(group.MessagingSystem, configInfo.getAttribute("source"), configInfo.getAttribute("connection"), configInfo.getAttribute("processingFailureQueue"), configInfo.getAttribute("historyQueue", ""));
					Application.currentApp.Log.println(Application.NORMAL_STARTUP_LOG_LEVEL,"Listening for incoming {0} messages on connection {1}, source {2}.  Failures will be placed in {3}",msgSys,configInfo.getAttribute("source"), configInfo.getAttribute("connection"), configInfo.getAttribute("processingFailureQueue"));

					foreach(XmlNode n in configInfo.Element.ChildNodes)
					{
						if(n is XmlElement)
						{
							XmlElement el = (XmlElement)n;
							bool observerReply = false;
							if(el.HasAttribute("reply"))
								try
								{
									observerReply = bool.Parse(el.GetAttribute("reply"));
								}
								catch(Exception e)
								{
									app.Log.println(Application.NORMAL_STARTUP_LOG_LEVEL,"Invalid value for 'reply' attribute: {0}.  Should be either 'true' or 'false'.  'false' is the default if not specified", el.GetAttribute("reply"));
								}
							string matchPattern = null;
							if(el.HasAttribute("matchPattern"))
								matchPattern = el.GetAttribute("matchPattern");
							bool isDefault=false;
							if (el.HasAttribute("default"))
							{
								try
								{
									isDefault = bool.Parse(el.GetAttribute("default"));
								}
								catch(Exception)
								{
								}
							}
							ICall observer = (ICall) callFactory.createFromNickName(n.Name, "", el);
							if (observer != null)
							{
								listener.addObserver(observer, el.GetAttribute("formatter"), observerReply, matchPattern, el.HasAttribute("encrypt") ? el.GetAttribute("encrypt"): "none", isDefault);
								Application.currentApp.Log.println(Application.NORMAL_STARTUP_LOG_LEVEL,"		Registered handler for messaging listener: Handler Type={0}, Definition={1}",el.Name,el.OuterXml);
							}
						}
						group.addListener(listener);
					}
				}
				else
					app.Log.println(Application.NORMAL_STARTUP_LOG_LEVEL,"No messaging system was defined for the group of listeners this listener is in on line {0} in file {1}", configInfo.LineNumber, configInfo.Context["filename"]);
			}
			catch (Exception e)
			{
				app.Log.println(Application.NORMAL_STARTUP_LOG_LEVEL,"Unable to process message listener: {0}", e);
			}
		}	
	}

    class ListenerGroupConfigHandler : ConfigHandler
	{
		protected MessagingListenerManager m_mgr;
		protected static string[] s_legalAttributes = new string[] {"messagingSystem"};
		public ListenerGroupConfigHandler(MessagingListenerManager mgr)
		{
			m_mgr = mgr;
		}
		public override void executeBefore(IConfigElement configInfo)
		{
			IApplication app = (IApplication)configInfo.Context["app"];
			try
			{
				configInfo.checkIllegalAttributes(s_legalAttributes);
				string msgSysName = configInfo.getAttribute("messagingSystem");
				if(msgSysName.Length != 0)
				{
					MessagingListenerGroup group = m_mgr.createListenerGroup(msgSysName);
					configInfo.Context["MessagingSystem"] = msgSysName;
					configInfo.Context["MessagingGroup"] = group;
				}
				else
				{
					//For a given group of messaging listeners, a messaging system needs to be defined to know which physical implementation
					//of the queueing system should be used.  Without that, it isn't possible to create objects needed.
					//TODO: Should an error be thrown....
					app.Log.println(Application.NORMAL_STARTUP_LOG_LEVEL,"No MessagingSystem attribute was specified for the MessagingListeners group defined on line {0} in file {1}", configInfo.LineNumber, configInfo.Context["filename"]);
				}
			}
			catch (Exception e)
			{
				app.Log.println(Application.NORMAL_STARTUP_LOG_LEVEL,"Exception {0}, occurred. The stack trace was {1}",e.Message,e.StackTrace.ToString());
			}
		}
	}
}
